package com.csust.automaticteach.app.student.learnchat;

import com.alibaba.cloud.ai.dashscope.api.DashScopeResponseFormat;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import com.csust.automaticteach.app.advisor.ReReadingAdvisor;
import com.csust.automaticteach.app.rag.config.VectorStoreDelegate;
import com.csust.automaticteach.model.entity.PromptSelf;
import com.csust.automaticteach.model.enums.BizTypeEnum;
import com.csust.automaticteach.service.ChatHistoryService;
import com.csust.automaticteach.service.PromptSelfService;
import com.csust.automaticteach.utils.GenericEntityConverter;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.ChatClientResponse;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.document.Document;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;

import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;


/**
 * @ClassName LearnApp
 * @Description 在线学习助手
 * @Author钰玟
 * @Date 2025/6/12 下午4:40
 * @Version 1.0
 **/
@Component
@Slf4j
public class OnlineLearnApp {
    private final ChatClient chatClient;
    private final ChatMemory redisChatMemory;
    private final ChatHistoryService chatHistoryService;
    private final PromptTemplate customSystemPrompt;
    private final PromptTemplate deepThinkPromptTemplate;
    private final PromptSelfService promptSelfService;

    public OnlineLearnApp(
            @Qualifier("dashscopeChatModel") ChatModel chatModel,
            @Qualifier("onlineLearnPrompt") PromptTemplate onlineLearnPrompt,
            @Qualifier("customSystemPrompt") PromptTemplate customSystemPrompt,
            @Qualifier("deepThinkPromptTemplate") PromptTemplate deepThinkPromptTemplate,
            ChatMemory redisChatMemory,
            @Lazy ChatHistoryService chatHistoryService,
            PromptSelfService promptSelfService,
            SimpleLoggerAdvisor simpleLoggerAdvisor,
            MessageChatMemoryAdvisor redisChatMemoryAdvisor) {
        this.promptSelfService = promptSelfService;
        this.customSystemPrompt = customSystemPrompt;
        this.deepThinkPromptTemplate = deepThinkPromptTemplate;
        this.redisChatMemory = redisChatMemory;
        this.chatHistoryService = chatHistoryService;
        this.chatClient = ChatClient.builder(chatModel)
                .defaultSystem(onlineLearnPrompt.getTemplate())//系统预设
                .defaultAdvisors(redisChatMemoryAdvisor,//添加对话记忆advisor
                        simpleLoggerAdvisor
                )
                .build();
    }

    /**
     * 支持多轮对话记忆的 聊天 流式输出 且支持用户选择prompt
     *
     * @param message 用户的问题
     * @param learnChatId  会话id
     * @param promptId  用户选择的promptId
     * @return Flux<String>
     */
    public Flux<String> ChatToLearn(String message,
                                    String model,
                                    Long learnChatId,
                                    String promptId) {
        //创建模型选项参数
        var runtimeOptions = DashScopeChatOptions.builder()
                .withModel(model)//选定模型
                .withTemperature(0.8)
                .withResponseFormat(DashScopeResponseFormat.builder()
                        .type(DashScopeResponseFormat.Type.TEXT)
                        .build()
                ).build();
        //加载对应的对话记忆
        chatHistoryService.loadChatHistoryToMemory(learnChatId, BizTypeEnum.CHAT_LEARN.getValue(), redisChatMemory,10);
        //获取用户选择的prompt
        PromptSelf promptSelf = null;
        //判断 promptId 是否为 0 人为约定 0 为 未选择prompt
        if (!(promptId == null || Long.parseLong(promptId) == 0L)) {
            //根据promptId 获取prompt
            promptSelf = promptSelfService.getById(promptId);
        }
        //拼接用户选择的prompt
        Prompt prompt = this.concatSelectedPrompt(promptSelf, message);
        return chatClient.prompt(prompt)
                .options(runtimeOptions)
                .advisors(memoryAdvisor -> memoryAdvisor
                        .param(ChatMemory.CONVERSATION_ID, learnChatId))
                .stream()
                .content();
    }
    /**
     * 支持多轮对话记忆的 聊天 流式输出 且支持用户选择prompt
     *
     * @param message 用户的问题
     * @param learnChatId  会话id
     * @param promptId  用户选择的promptId
     * @return Flux<String>
     */
    public Flux<String> DeepThinkingChatToLearn(String message,
                                    String model,
                                    Long learnChatId,
                                    String promptId) {
        //创建模型选项参数
        var runtimeOptions= DashScopeChatOptions.builder()
                .withModel(model)//选定模型
                .withTemperature(0.8)
                .withResponseFormat(DashScopeResponseFormat.builder()
                        .type(DashScopeResponseFormat.Type.TEXT)
                        .build()
                ).build();
        //加载对应的对话记忆
        chatHistoryService.loadChatHistoryToMemory(learnChatId, BizTypeEnum.CHAT_LEARN.getValue(), redisChatMemory,10);
        //获取用户选择的prompt
        PromptSelf promptSelf = null;
        //判断 promptId 是否为 0 人为约定 0 为 未选择prompt
        if (!(promptId == null || Long.parseLong(promptId) == 0L)) {
            //根据promptId 获取prompt
            promptSelf = promptSelfService.getById(promptId);
        }
        //拼接用户选择的prompt
        Prompt prompt = this.concatSelectedPrompt(promptSelf, message);
        return chatClient.prompt(prompt)
                .options(runtimeOptions)
                .system(deepThinkPromptTemplate.getTemplate())
                .advisors(memoryAdvisor -> memoryAdvisor
                        .param(ChatMemory.CONVERSATION_ID, learnChatId))
                .stream()
                .content();
    }

    @Resource
    private ToolCallback[] allTools;
    public String doChatWithTools(String message, String chatId) {
        ChatResponse response = chatClient
                .prompt()
                .user(message)
                .advisors(memoryAdvisor -> memoryAdvisor
                        .param(ChatMemory.CONVERSATION_ID, chatId))
                .tools(allTools)
                .call()
                .chatResponse();
        String content = response.getResult().getOutput().getText();
        log.info("content: {}", content);
        return content;
    }

    /**
     * 拼接用户选择的自定义的prompt
     *
     * @param promptSelf 自定义的prompt
     * @param userText   用户的问题
     * @return 拼接后的prompt
     */
    private Prompt concatSelectedPrompt(PromptSelf promptSelf,String userText) {
        if(promptSelf == null){
            return new Prompt(new UserMessage(userText));
        }
        Map<String, Object> variables = GenericEntityConverter.entityToMap(promptSelf);
        Message userMessage = new UserMessage(userText);
        Message systemMessage = customSystemPrompt.createMessage(variables);
        return new Prompt(List.of(systemMessage,userMessage));
    }

    /**
     * 思考过程处理
     * @param chatResponseFlux 思考过程
     * @return Flux<String>
     */
    private Flux<String> processFluxWithReasoning(Flux<ChatResponse> chatResponseFlux){
        //提取思考过程
        return chatResponseFlux.map(
                chatResponse -> {
                    AssistantMessage output = chatResponse.getResults().get(0).getOutput();
                    Object o = output.getMetadata().get("reasoningContent");
                    String reasoningContent = String.valueOf(o);
                    return StringUtils.hasText(reasoningContent)
                            ? String.format("<think>%s</think>", reasoningContent) + output.getText()
                            : output.getText();
                }
        );
    }
}
